/**
 * 
 */
package gui.views;

import gui.LibraryComboBox;
import gui.TypeComboBox;
import gui.TypeList;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;

import metagrammar.Operator;
import metagrammar.OperatorDescription;
import application.Application;
import application.GlobalContext;

/**
 * @author Joshua Lockerman
 *
 */
public class CreateOperatorView extends JFrame {
    
    private final GlobalContext context;
    private JTextField operatorName;
    private JTextArea typeDescription;
    
    private final DefaultListModel<metagrammar.Type> inputTuple;
    private final LibraryComboBox librarySelector;
    private TypeComboBox result;
    
    public CreateOperatorView()
    {
        super("Create Operator");
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        context = Application.injector.getInstance(GlobalContext.class);
        
        inputTuple = new DefaultListModel<metagrammar.Type>();
        
        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
        
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        
        librarySelector = new LibraryComboBox();
        
        add(createRelationCreatorPanel());
        
        add(Box.createGlue());
        
        add(Box.createVerticalStrut(15));
        JPanel spacer = new JPanel();
        spacer.setLayout(new BoxLayout(spacer, BoxLayout.X_AXIS));
        spacer.add(Box.createHorizontalStrut(15));
        spacer.add(createTextPanel());
        spacer.add(Box.createHorizontalStrut(15));
        add(spacer);
        add(Box.createVerticalStrut(15));
        
        add(createButtonPanel());
        
        pack();
        setMinimumSize(getSize());
    }
    
    private Component createRelationCreatorPanel()
    {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createTitledBorder("Relation"));
        
        JPanel spacer = new JPanel(new FlowLayout(FlowLayout.LEADING));
        spacer.add(librarySelector);
        panel.add(spacer, BorderLayout.NORTH);
        panel.add(createRelationPanel(), BorderLayout.CENTER);
        
        return panel;
    }
    
    /**
     * @param panel
     * @return 
     */
    private Component createRelationPanel()
    {
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout(FlowLayout.CENTER));
        
        panel.add(createTupleTypeList());
        
        final JList<metagrammar.Type> inputList = new JList<metagrammar.Type>(inputTuple);
        inputList.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                    inputTuple.removeElementAt(inputList.getSelectedIndex());
                    //TODO
                }
            }
        });
        JScrollPane inputScroll = new JScrollPane(inputList);
        inputList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        inputList.setBorder(BorderFactory.createTitledBorder("Input Tuple"));
        Dimension dim = new Dimension(85, 80);
        inputScroll.setMinimumSize(dim);
        inputScroll.setPreferredSize(dim);
        inputScroll.setBorder(BorderFactory.createEmptyBorder());
        panel.add(inputScroll);
        
        panel.add(Box.createHorizontalStrut(10));
        
        JLabel arrow = new JLabel("→");
        arrow.setFont(arrow.getFont().deriveFont(20f));
        panel.add(arrow);
        
        panel.add(Box.createHorizontalStrut(10));
        
        result = librarySelector.createTypeComboBox();
        result.setBorder(BorderFactory.createTitledBorder("Result"));
        panel.add(result);
        
        return panel;
    }
    
    private Component createTupleTypeList()
    {
        final TypeList typeList = librarySelector.createTypeList();
        MouseListener doubleClickListener = new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if(SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
                    inputTuple.addElement(typeList.getSelectedValue());
                    //TODO
                }
            }
        };
        typeList.addMouseListener(doubleClickListener);
        JScrollPane scroll = new JScrollPane(typeList);
        return scroll;
    }
    
    private Component createTextPanel()
    {
        JPanel textPanel = new JPanel();
        textPanel.setLayout(new BorderLayout());
        textPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
        
        operatorName = new JTextField();
        operatorName.setEditable(true);
        operatorName.setBorder(BorderFactory.createTitledBorder("Name"));
        textPanel.add(operatorName, BorderLayout.NORTH);
        
        typeDescription = new JTextArea(5, 0);
        typeDescription.setEditable(true);
        typeDescription.setLineWrap(false);
        JScrollPane scroll = new JScrollPane(typeDescription,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scroll.setBorder(BorderFactory.createTitledBorder("Description"));
        textPanel.add(scroll, BorderLayout.CENTER);
        
        return textPanel;
    }
    
    /**
     * @return
     */
    private JPanel createButtonPanel()
    {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        
        JButton okButton = new JButton();
        okButton.setAction(new AbstractAction("Create") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                createOperator();
            }
        });
        buttonPanel.add(okButton);
        
        JButton cancelButton = new JButton();
        cancelButton.setAction(new AbstractAction("Cancel") {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                dispose();
            }
        });
        buttonPanel.add(cancelButton);
        return buttonPanel;
    }
    
    private void createOperator()
    {
        if(result == null) {
            JOptionPane.showMessageDialog(this, "There must be a result Type for the relation.",
                    "Operator creation error.", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        Operator newOperator;
        metagrammar.Type resultType = result.getItemAt(result.getSelectedIndex());
        if(inputTuple.isEmpty()) {
            newOperator = new Operator(resultType);
        }
        else {
            metagrammar.Type[] input = new metagrammar.Type[inputTuple.size()];
            inputTuple.copyInto(input);
            newOperator = new Operator(resultType, input);
        }
        
        String name = operatorName.getText();
        String description = typeDescription.getText();
        OperatorDescription operatorDescription = new OperatorDescription(newOperator, name,
                description);
        
        context.add(newOperator);
        context.add(operatorDescription);
        int response = JOptionPane.showConfirmDialog(this, "Operator " + newOperator
                + " added.\nWould you like to create a human readable version now?",
                "Operator added.", JOptionPane.YES_NO_OPTION);
        if(response == JOptionPane.YES_OPTION) {
            CreateSpecView create = new CreateSpecView(newOperator);
            create.setVisible(true);
        }
        dispose();
    }
}
